package mongotesting

import (
	"context"
	"fmt"
	"log"
	"testing"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/go-connections/nat"
)

func RunWithMongoInDocker(m *testing.M, mongoURI *string) int {
	cli, err := client.NewClientWithOpts(client.FromEnv)
	if err != nil {
		panic(err)
	}

	resp, err := cli.ContainerCreate(
		context.Background(),
		&container.Config{
			Image: "mongo:4",
			ExposedPorts: nat.PortSet{
				"27017/tcp": {},
			},
		}, &container.HostConfig{
			PortBindings: nat.PortMap{
				"27017/tcp": []nat.PortBinding{
					{
						HostIP: "127.0.0.1",
						//HostPort: "27018",
						HostPort: "0", // 会自动映射到一个端口
					},
				},
			},
		}, nil, nil, "")

	defer func() {
		err = cli.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{
			Force: true,
		})
		if err != nil {
			log.Fatalf("remove container failed: %v", err)
		}

		fmt.Println("container stop", resp.ID)
	}()
	if err != nil {
		panic(err)
	}

	err = cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{})
	if err != nil {
		panic(err)
	}

	fmt.Println("container started", resp.ID)

	// 查看映射到了哪个端口
	inspRes, err := cli.ContainerInspect(context.Background(), resp.ID)
	if err != nil {
		panic(err)
	}
	hostPort := inspRes.NetworkSettings.Ports["27017/tcp"][0]
	fmt.Println("容器的端口映射在: ", inspRes.NetworkSettings.Ports)
	*mongoURI = fmt.Sprintf("mongodb://%s:%s", hostPort.HostIP, hostPort.HostPort)

	return m.Run()
}

func SetupIndexes(c context.Context, d *mongo.Database) error {
	_, err := d.Collection("account").Indexes().CreateOne(c, mongo.IndexModel{
		Keys: bson.D{
			{
				Key:   "opend_id",
				Value: 1,
			},
		},
		Options: options.Index().SetUnique(true),
	})

	if err != nil {
		return err
	}

	_, err = d.Collection("trip").Indexes().CreateOne(c, mongo.IndexModel{
		Keys: bson.D{
			{
				Key:   "trip.accountid",
				Value: 1,
			},
			{
				Key:   "trip.status",
				Value: 1,
			},
		},
		Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{
			"trip.status": 1,
		}),
	})

	if err != nil {
		return err
	}

	_, err = d.Collection("profile").Indexes().CreateOne(c, mongo.IndexModel{
		Keys: bson.D{
			{
				Key:   "accountid",
				Value: 1,
			},
		},
		Options: options.Index().SetUnique(true),
	})
	return err
}
